package com.zeus.core.report;

import com.zeus.common.utils.DateUtils;
import com.zeus.common.utils.HashUtils;
import com.zeus.common.utils.MarkdownUtils;
import com.zeus.core.context.ZeusContext;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 开放API 抽象类
 *
 * @author f1ybear_wang  2022/3/2 7:33 下午
 */
public abstract class AbstractOpenApiZeusReportClient extends AbstractZeusReportClient {
    /**
     * 扩展信息是否已经初始化
     */
    protected boolean parsingExtendInit;

    /**
     * 报警内容
     */
    protected String message;

    /**
     * 解决办法
     */
    protected String solution;

    /**
     * 类名
     */
    protected String className;

    /**
     * 方法名
     */
    protected String methodName;

    /**
     * 行数
     */
    protected String lineNumber;

    /**
     * 文件名
     */
    protected String fileName;

    /**
     * 参数名
     */
    protected String[] argNames;

    /**
     * 参数
     */
    protected Object[] args;

    /**
     * 异常信息
     */
    protected String exceptionMessage;

    /**
     * 异常堆栈
     */
    protected String stackTrace;

    public AbstractOpenApiZeusReportClient() {
        super();
    }

    @Override
    public String uniqueCode() {
        if (!this.parsingExtendInit) {
            parsingExtend();
        }

        if (this.methodName != null && !this.methodName.isEmpty()) {
            if (this.fileName != null && !this.fileName.isEmpty()) {
                return String.valueOf(HashUtils.bkdrHash(this.fileName + this.methodName + this.lineNumber));
            } else if (this.className != null && !this.className.isEmpty()) {
                return String.valueOf(HashUtils.bkdrHash(this.className + this.methodName + this.lineNumber));
            }
        }

        if (this.gatherRule.alarmLevel() != null && message != null) {
            return String.valueOf(HashUtils.bkdrHash(this.gatherRule.alarmLevel().getCode() + this.message));
        }
        return null;
    }

    @Override
    protected String workDingTalkMessage() {
        // 组装提醒内容字符串
        StringBuilder sb = new StringBuilder();
        // 标题
        sb.append(getTitle());

        // 加工基本指标
        sb.append(MarkdownUtils.getItem("时间", DateUtils.getSimpleString(this.occurrenceTime)));
        if (super.traceIdIsNotEmpty()) {
            sb.append(MarkdownUtils.getItem("traceId", this.traceId));
        }
        sb.append(MarkdownUtils.getItem("ELK", super.getElkUrl()));
        sb.append(MarkdownUtils.getItem("类信息", this.getClassInfo()));
        sb.append(MarkdownUtils.getItem("报警内容", getMessage(this.message)));
        sb.append(MarkdownUtils.getItem("解决办法", this.solution));
        sb.append(MarkdownUtils.getItem("异常信息", getExceptionMessage(this.exceptionMessage)));
        sb.append(MarkdownUtils.getItem("堆栈信息", getStackTrace(this.stackTrace)));
        sb.append(MarkdownUtils.getItem("请求参数", this.getArgsString()));
        sb.append(MarkdownUtils.getItem("请求应用", getRequestApp()));
        sb.append(MarkdownUtils.getItem("请求IP", getRequestIp()));
        sb.append(MarkdownUtils.getItem("部署Tag", ZeusContext.getContext().getDeployTag()));
        sb.append(MarkdownUtils.getItem("服务器IP", ZeusContext.getContext().getHostIp()));
        sb.append(MarkdownUtils.getItem("服务器名称", ZeusContext.getContext().getHostName()));
        return sb.toString();
    }

    /**
     * 获取类信息
     *
     * @return 类信息
     * @author f1ybear_wang  2022/3/2 8:09 下午
     */
    private String getClassInfo() {
        return Stream.of(Optional.ofNullable(this.className).orElse(this.fileName), this.methodName, this.lineNumber)
            .filter(e -> e != null && !e.isEmpty()).collect(Collectors.joining("#"));
    }

    /**
     * 获取参数信息
     *
     * @return 类信息
     * @author f1ybear_wang  2022/3/2 8:09 下午
     */
    private String getArgsString() {
        // 获取入参
        if (this.argNames != null && this.args != null && this.argNames.length > 0 && this.args.length > 0) {
            Map<String, Object> paramMap = new HashMap<>(this.args.length);
            for (int i = 0; i < this.args.length; i++) {
                Object arg = this.args[i];
                if (arg instanceof Serializable) {
                    paramMap.put(this.argNames[i], this.args[i]);
                }
            }
            return paramMap.toString();
        }
        return null;
    }
}
